/**
 * @create 2022-05-02
 * @desc 改成往前面插入一个新的 console，更美观
 */

const {getBaseData} = require('../utils/index')

const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generate = require('@babel/generator').default;
const types = require('@babel/types');
const template = require('@babel/template').default;

const {sourceCode, outputFn} = getBaseData();

const ast = parser.parse(sourceCode, {
    sourceType: 'unambiguous',
    plugins: ['jsx']
});

const calleeNames = ['log', 'error', 'warn', 'info'].map(name => `console.${name}`);
traverse(ast, {
    CallExpression(path, state) {
        const {node} = path;
        const calleeCode = generate(node.callee).code;

        // 1. 插入了新节点后，babel 会继续遍历新节点，通过 isNewConsole 标记跳过
        // 2. jsx 节点不能直接插入，需要用 [] 包起来
        // 3. 单行的箭头行数，也不能往前插入，这里用 () 处理
        if (!node.isNewConsole && calleeNames.includes(calleeCode)) {
            const {line, column} = node.callee.loc.start;
            const newNode = template.expression(`console.log("[info]: line: ${line}, column: ${column}: ")`)();
            newNode.isNewConsole = true;

            if (path.findParent(p => p.isJSXElement())) {
                path.replaceWith(types.arrayExpression([newNode, node]))
                path.skip();
            } else if (path.findParent(p => p.isArrowFunctionExpression())) {
                const ArrowFunctionParent = path.findParent(p => p.isArrowFunctionExpression());
                const start = ArrowFunctionParent.node.loc.start;
                if (line === start.line) { // 判断是否是同一行
                    path.replaceWith(types.sequenceExpression([newNode, node]))
                    path.skip();
                } else {
                    path.insertBefore(newNode);
                }
            } else {
                path.insertBefore(newNode);
            }
        }
    }
});

const { code, map } = generate(ast);
outputFn(code)